home *** CD-ROM | disk | FTP | other *** search
/ Workbench Add-On / Workbench Add-On - Volume 1.iso / Text / Show / Less / less-252 / filename.c < prev    next >
C/C++ Source or Header  |  1994-10-15  |  11KB  |  586 lines

  1. /*
  2.  * Copyright (c) 1984,1985,1989,1994  Mark Nudelman
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice in the documentation and/or other materials provided with 
  12.  *    the distribution.
  13.  *
  14.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
  15.  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  16.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
  17.  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE
  18.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
  19.  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
  20.  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 
  21.  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
  22.  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
  23.  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 
  24.  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25.  */
  26.  
  27.  
  28. /*
  29.  * Routines to mess around with filenames (and files).
  30.  * Much of this is very OS dependent.
  31.  */
  32.  
  33. #include "less.h"
  34. #if MSOFTC
  35. #include <dos.h>
  36. #endif
  37.  
  38. extern int force_open;
  39. extern IFILE curr_ifile;
  40. extern IFILE old_ifile;
  41.  
  42. /*
  43.  * Return the full pathname of the given file in the "home directory".
  44.  */
  45.     public char *
  46. homefile(filename)
  47.     char *filename;
  48. {
  49.     register char *pathname;
  50.     register char *homedir;
  51.  
  52.     homedir = getenv("HOME");
  53. #if MSOFTC
  54.     /*
  55.      * If $HOME is not defined, look for the file anywhere on search path.
  56.      */
  57.     pathname = NULL;
  58.     if (homedir != NULL)
  59.     {
  60.         /*
  61.          * Found $HOME.
  62.          */
  63.         pathname = (char *) calloc(strlen(homedir)+strlen(filename)+2, 
  64.                     sizeof(char));
  65.         if (pathname == NULL)
  66.             return (NULL);
  67.         sprintf(pathname, "%s\\%s", homedir, filename);
  68.         if (access(pathname, 0) < 0)
  69.         {
  70.             free(pathname);
  71.             pathname = NULL;
  72.         }
  73.     }
  74.     if (pathname == NULL)
  75.     {
  76.             
  77.         pathname = (char *) calloc(_MAX_PATH, sizeof(char));
  78.         _searchenv(filename, "PATH", pathname);
  79.         if (*pathname == '\0')
  80.             
  81.         {
  82.             free(pathname);
  83.             pathname = NULL;
  84.         }
  85.     }
  86.     
  87. #else
  88.     if (homedir == NULL)
  89.         return (NULL);
  90.     pathname = (char *) calloc(strlen(homedir)+strlen(filename)+2,
  91.                 sizeof(char));
  92.     if (pathname == NULL)
  93.         return (NULL);
  94.     sprintf(pathname, "%s/%s", homedir, filename);
  95. #endif
  96.     return (pathname);
  97. }
  98.  
  99. /*
  100.  * Find out where the help file is.
  101.  */
  102.     public char *
  103. find_helpfile()
  104. {
  105.     register char *helpfile;
  106.     
  107.     if ((helpfile = getenv("LESSHELP")) != NULL)
  108.         return (save(helpfile));
  109. #if MSOFTC
  110.     return (homefile(HELPFILE));
  111. #else
  112.     return (save(HELPFILE));
  113. #endif
  114. }
  115.  
  116. /*
  117.  * Expand a string, substituting any "%" with the current filename,
  118.  * and any "#" with the previous filename.
  119.  * {{ This is a lot of work just to support % and #. }}
  120.  */
  121.     public char *
  122. fexpand(s)
  123.     char *s;
  124. {
  125.     register char *fr, *to;
  126.     register int n;
  127.     register char *e;
  128.  
  129.     /*
  130.      * Make one pass to see how big a buffer we 
  131.      * need to allocate for the expanded string.
  132.      */
  133.     n = 0;
  134.     for (fr = s;  *fr != '\0';  fr++)
  135.     {
  136.         switch (*fr)
  137.         {
  138.         case '%':
  139.             n += strlen(get_filename(curr_ifile));
  140.             break;
  141.         case '#':
  142.             if (old_ifile == NULL_IFILE)
  143.             {
  144.                 error("No previous file", NULL_PARG);
  145.                 return (NULL);
  146.             }
  147.             n += strlen(get_filename(old_ifile));
  148.             break;
  149.         default:
  150.             n++;
  151.             break;
  152.         }
  153.     }
  154.  
  155.     e = (char *) ecalloc(n+1, sizeof(char));
  156.  
  157.     /*
  158.      * Now copy the string, expanding any "%" or "#".
  159.      */
  160.     to = e;
  161.     for (fr = s;  *fr != '\0';  fr++)
  162.     {
  163.         switch (*fr)
  164.         {
  165.         case '%':
  166.             strcpy(to, get_filename(curr_ifile));
  167.             to += strlen(to);
  168.             break;
  169.         case '#':
  170.             strcpy(to, get_filename(old_ifile));
  171.             to += strlen(to);
  172.             break;
  173.         default:
  174.             *to++ = *fr;
  175.             break;
  176.         }
  177.     }
  178.     *to = '\0';
  179.     return (e);
  180. }
  181.  
  182. #if TAB_COMPLETE_FILENAME
  183.  
  184. /*
  185.  * Return a blank-separated list of filenames which "complete"
  186.  * the given string.
  187.  */
  188.     public char *
  189. fcomplete(s)
  190.     char *s;
  191. {
  192.     char *fpat;
  193.     /*
  194.      * Complete the filename "s" by globbing "s*".
  195.      */
  196. #if MSOFTC
  197.     /*
  198.      * But in DOS, we have to glob "s*.*".
  199.      * But if the final component of the filename already has
  200.      * a dot in it, just do "s*".  
  201.      * (Thus, "FILE" is globbed as "FILE*.*", 
  202.      *  but "FILE.A" is globbed as "FILE.A*").
  203.      */
  204.     char *slash;
  205.     for (slash = s+strlen(s)-1;  slash > s;  slash--)
  206.         if (*slash == '/' || *slash == '\\')
  207.             break;
  208.     fpat = (char *) ecalloc(strlen(s)+4, sizeof(char));
  209.     if (strchr(slash, '.') == NULL)
  210.         sprintf(fpat, "%s*.*", s);
  211.     else
  212.         sprintf(fpat, "%s*", s);
  213. #else
  214.     fpat = (char *) ecalloc(strlen(s)+2, sizeof(char));
  215.     sprintf(fpat, "%s*", s);
  216. #endif
  217.     s = glob(fpat);
  218.     if (s != NULL && strcmp(s,fpat) == 0)
  219.     {
  220.         free(s);
  221.         s = NULL;
  222.     }
  223.     free(fpat);
  224.     return (s);
  225. }
  226. #endif
  227.  
  228. /*
  229.  * Try to determine if a file is "binary".
  230.  * This is just a guess, and we need not try too hard to make it accurate.
  231.  */
  232.     public int
  233. bin_file(f)
  234.     int f;
  235. {
  236.     int i;
  237.     int n;
  238.     unsigned char data[64];
  239.  
  240.     n = read(f, data, sizeof(data));
  241.     for (i = 0;  i < n;  i++)
  242.         if (binary_char(data[i]))
  243.             return (1);
  244.     return (0);
  245. }
  246.  
  247. /*
  248.  * Try to determine the size of a file by seeking to the end.
  249.  */
  250.     static POSITION
  251. seek_filesize(f)
  252.     int f;
  253. {
  254.     off_t spos;
  255.  
  256.     spos = lseek(f, (off_t)0, 2);
  257.     if (spos == BAD_LSEEK)
  258.         return (NULL_POSITION);
  259.     return ((POSITION) spos);
  260. }
  261.  
  262. /*
  263.  * Expand a filename, substituting any environment variables, etc.
  264.  */
  265. #if GLOB
  266.  
  267. FILE *popen();
  268.  
  269.     static char *
  270. readfd(fd)
  271.     FILE *fd;
  272. {
  273.     int len;
  274.     int ch;
  275.     char *buf;
  276.     char *p;
  277.     
  278.     len = 100;
  279.     buf = (char *) ecalloc(len, sizeof(char));
  280.     for (p = buf;  ;  p++)
  281.     {
  282.         if ((ch = getc(fd)) == '\n' || ch == EOF)
  283.             break;
  284.         if (p - buf >= len-1)
  285.         {
  286.             len *= 2;
  287.             *p = '\0';
  288.             p = (char *) ecalloc(len, sizeof(char));
  289.             strcpy(p, buf);
  290.             free(buf);
  291.             buf = p;
  292.             p = buf + strlen(buf);
  293.         }
  294.         *p = ch;
  295.     }
  296.     *p = '\0';
  297.     return (buf);
  298. }
  299.  
  300.     static FILE *
  301. shellcmd(cmd, s1, s2)
  302.     char *cmd;
  303.     char *s1;
  304.     char *s2;
  305. {
  306.     char *scmd;
  307.     char *scmd2;
  308.     char *shell;
  309.     FILE *fd;
  310.     int len;
  311.     
  312.     len = strlen(cmd) + 
  313.         (s1 == NULL ? 0 : strlen(s1)) + 
  314.         (s2 == NULL ? 0 : strlen(s2)) + 1;
  315.     scmd = (char *) ecalloc(len, sizeof(char));
  316.     sprintf(scmd, cmd, s1, s2);
  317.     shell = getenv("SHELL");
  318.     if (shell != NULL && *shell != '\0')
  319.     {
  320.         /*
  321.          * Read the output of <$SHELL -c "cmd">.
  322.          */
  323.         scmd2 = (char *) ecalloc(strlen(shell) + strlen(scmd) + 7,
  324.                     sizeof(char));
  325.         sprintf(scmd2, "%s -c \"%s\"", shell, scmd);
  326.         free(scmd);
  327.         scmd = scmd2;
  328.     }
  329.  
  330.     fd = popen(scmd, "r");
  331.     free(scmd);
  332.     return (fd);
  333. }
  334.  
  335.     public char *
  336. glob(filename)
  337.     char *filename;
  338. {
  339.     FILE *fd;
  340.     char *gfilename;
  341.  
  342.     filename = fexpand(filename);
  343.     if (filename == NULL)
  344.         return (NULL);
  345.  
  346.     /*
  347.      * We get the shell to expand the filename for us by passing
  348.      * an "echo" command to the shell and reading its output.
  349.      */
  350.     fd = shellcmd("echo %s", filename, (char*)NULL);
  351.     if (fd == NULL)
  352.     {
  353.         /*
  354.          * Cannot create the pipe.
  355.          * Just return the original (fexpanded) filename.
  356.          */
  357.         return (filename);
  358.     }
  359.     free(filename);
  360.     gfilename = readfd(fd);
  361.     pclose(fd);
  362.     if (*gfilename == '\0')
  363.         return (NULL);
  364.     return (gfilename);
  365. }
  366.  
  367.     public char *
  368. open_altfile(filename)
  369.     char *filename;
  370. {
  371.     char *lessopen;
  372.     char *gfilename;
  373.     FILE *fd;
  374.     
  375.     if ((lessopen = getenv("LESSOPEN")) == NULL)
  376.         return (NULL);
  377.     filename = fexpand(filename);
  378.     if (filename == NULL)
  379.         return (NULL);
  380.     fd = shellcmd(lessopen, filename, (char*)NULL);
  381.     if (fd == NULL)
  382.     {
  383.         /*
  384.          * Cannot create the pipe.
  385.          */
  386.         return (NULL);
  387.     }
  388.     free(filename);
  389.     gfilename = readfd(fd);
  390.     pclose(fd);
  391.     if (*gfilename == '\0')
  392.         return (NULL);
  393.     return (gfilename);
  394. }
  395.  
  396.     public void
  397. close_altfile(altfilename, filename)
  398.     char *altfilename;
  399.     char *filename;
  400. {
  401.     char *lessclose;
  402.     FILE *fd;
  403.     
  404.     if ((lessclose = getenv("LESSCLOSE")) == NULL)
  405.              return;
  406.     fd = shellcmd(lessclose, filename, altfilename);
  407.     pclose(fd);
  408. }
  409.         
  410. #else
  411. #if MSOFTC
  412.  
  413.     public char *
  414. glob(filename)
  415.     char *filename;
  416. {
  417.     register char *gfilename;
  418.     register char *p;
  419.     register int len;
  420.     register int n;
  421.     struct find_t fnd;
  422.     char drive[_MAX_DRIVE];
  423.     char dir[_MAX_DIR];
  424.     char fname[_MAX_FNAME];
  425.     char ext[_MAX_EXT];
  426.     
  427.     filename = fexpand(filename);
  428.     if (filename == NULL)
  429.         return (NULL);
  430.     if (_dos_findfirst(filename, ~0, &fnd) != 0)
  431.         return (filename);
  432.         
  433.     _splitpath(filename, drive, dir, fname, ext);
  434.     len = 100;
  435.     gfilename = (char *) ecalloc(len, sizeof(char));
  436.     p = gfilename;
  437.     do {
  438.         n = strlen(drive) + strlen(dir) + strlen(fnd.name);
  439.         while (p - gfilename + n+2 >= len)
  440.         {
  441.             len *= 2;
  442.             *p = '\0';
  443.             p = (char *) ecalloc(len, sizeof(char));
  444.             strcpy(p, gfilename);
  445.             free(gfilename);
  446.             gfilename = p;
  447.             p = gfilename + strlen(gfilename);
  448.         }
  449.         sprintf(p, "%s%s%s", drive, dir, fnd.name);
  450.         p += n;
  451.         *p++ = ' ';
  452.     } while (_dos_findnext(&fnd) == 0);
  453.     
  454.     *--p = '\0';
  455.     return (gfilename);
  456. }
  457.     
  458.     public char *
  459. open_altfile(filename)
  460.     char *filename;
  461. {
  462.     return (NULL);
  463. }
  464.  
  465.     public void
  466. close_altfile(altfilename, filename)
  467.     char *altfilename;
  468.     char *filename;
  469. {
  470. }
  471.         
  472. #else
  473.  
  474.     public char *
  475. glob(filename)
  476.     char *filename;
  477. {
  478.     return (fexpand(filename));
  479. }
  480.  
  481.     
  482.     public char *
  483. open_altfile(filename)
  484.     char *filename;
  485. {
  486.          return (NULL);
  487. }
  488.  
  489.     public void
  490. close_altfile(altfilename, filename)
  491.     char *altfilename;
  492.     char *filename;
  493. {
  494. }
  495.         
  496. #endif
  497. #endif
  498.  
  499.  
  500. #if HAVE_STAT
  501.  
  502. #include <sys/stat.h>
  503.  
  504. /*
  505.  * Returns NULL if the file can be opened and
  506.  * is an ordinary file, otherwise an error message
  507.  * (if it cannot be opened or is a directory, etc.)
  508.  */
  509.     public char *
  510. bad_file(filename)
  511.     char *filename;
  512. {
  513.     register char *m;
  514.     struct stat statbuf;
  515.  
  516.     if (stat(filename, &statbuf) < 0)
  517.         return (errno_message(filename));
  518.  
  519.     if (force_open)
  520.         return (NULL);
  521.  
  522.     if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
  523.     {
  524.         static char is_dir[] = " is a directory";
  525.         m = (char *) ecalloc(strlen(filename) + sizeof(is_dir), 
  526.             sizeof(char));
  527.         strcpy(m, filename);
  528.         strcat(m, is_dir);
  529.         return (m);
  530.     }
  531.     if ((statbuf.st_mode & S_IFMT) != S_IFREG)
  532.     {
  533.         static char not_reg[] = " is not a regular file";
  534.         m = (char *) ecalloc(strlen(filename) + sizeof(not_reg), 
  535.             sizeof(char));
  536.         strcpy(m, filename);
  537.         strcat(m, not_reg);
  538.         return (m);
  539.     }
  540.  
  541.     return (NULL);
  542. }
  543.  
  544. /*
  545.  * Return the size of a file, as cheaply as possible.
  546.  * In Unix, we can stat the file.
  547.  */
  548.     public POSITION
  549. filesize(f)
  550.     int f;
  551. {
  552.     struct stat statbuf;
  553.  
  554.     if (fstat(f, &statbuf) < 0)
  555.         /*
  556.          * Can't stat; try seeking to the end.
  557.          */
  558.         return (seek_filesize(f));
  559.  
  560.     return ((POSITION) statbuf.st_size);
  561. }
  562.  
  563. #else
  564.  
  565. /*
  566.  * If we have no way to find out, just say the file is good.
  567.  */
  568.     public char *
  569. bad_file(filename)
  570.     char *filename;
  571. {
  572.     return (NULL);
  573. }
  574.  
  575. /*
  576.  * We can find the file size by seeking.
  577.  */
  578.     public POSITION
  579. filesize(f)
  580.     int f;
  581. {
  582.     return (seek_filesize(f));
  583. }
  584.  
  585. #endif
  586.